package com.equipment.management.controller;


import com.equipment.management.dao.LogDao;
import com.equipment.management.dao.MainframeDao;
import com.equipment.management.dao.MessageDao;
import com.equipment.management.entity.Log;
import com.equipment.management.entity.Mainframe;
import com.equipment.management.entity.MainframeScan;
import com.equipment.management.entity.Message;
import com.equipment.management.mqtt.MqttGateway;
import com.equipment.management.service.MainframeService;
import com.equipment.management.util.Base64Util;
import com.equipment.management.util.Result;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping(value = "/mainframe")
public class MainframeController extends Base64Util {

    @Autowired
    private MainframeService mainframeService;

    @Autowired
    private MainframeDao mainframeDao;
    @Autowired
    private MqttGateway mqttGateway;
    @Resource
    private MessageDao messageDao;

    @Resource
    private LogDao logDao;

    @GetMapping("/all")
    public Object findAllMainframe(
            @RequestParam(name = "pageNum", required = false, defaultValue = "1")
                    int pageNum,
            @RequestParam(name = "pageSize", required = false, defaultValue = "10")
                    int pageSize,
            @RequestParam(name = "room_num", required = false)
                    String room_num
            ) {
        return mainframeService.findAllMainframe(pageNum, pageSize,room_num);
    }


    public void scan(Mainframe cron) throws MqttException, InterruptedException {
        String random=random();

        mqttGateway.sendToMqtt(random+"scan"+"#"+cron.getPayload(), "device_sub:"+cron.getCode());
        mqttGateway.sendToMqtt(random+"scan"+"#"+cron.getPayload(), "device_pub:"+cron.getCode());

        String code1="device_sub:"+cron.getCode();
        String code2="device_pub:"+cron.getCode();
        subscribe(code1,cron.getOperate(),random);
        subscribe(code2,cron.getOperate(),random);
        Thread.sleep(150000);
    }

    @PostMapping("/addMainframe")
    public Result addMainframe(@RequestBody Mainframe mainframe) throws Exception {
        log.info("新增设备参数：{}",mainframe);

        Mainframe us = mainframeService.getMainframeByCode(mainframe.getCode());
        if(us!=null){
            return new Result(300,"主机已存在");
        }
        if(0==mainframe.getState()){
            mainframe.setResult("close");

        }else if(1==mainframe.getState()){
            mainframe.setResult("");

        }
        int i=mainframeService.addMainframe(mainframe);
        mainframe.setCreate_time(new Date());


        if(i>0&&"定时".equals(mainframe.getType())){
            ScheduledTaskRegistrar scheduledTaskRegistrar=new ScheduledTaskRegistrar();
            scheduledTaskRegistrar.addTriggerTask(
                    //1.添加任务内容(Runnable)，可以为方法
                    () -> {
                        try {
                          scan(mainframe);
                        } catch (MqttException | InterruptedException e) {
                            e.printStackTrace();
                        }
                    },
                    //2.设置执行周期(Trigger)
                    triggerContext -> {
                        //2.1 从数据库获取执行周期，在这里调用不同的方法返回不同的定时任务信息
                        System.out.println(mainframe);
                        //2.2 合法性校验.
                        if (StringUtils.isEmpty(mainframe)) {
                            // Omitted Code ..
                            log.info("计划任务为空");
                            return  null;
                        }
                        //2.3 返回执行周期(Date)
                        return new CronTrigger(mainframe.getType()).nextExecutionTime(triggerContext);
                    }
            );
        }



        return i > 0?new Result(200,"添加成功"):new Result(500,"添加失败");

    }


    @PostMapping("/deleteMainframe")
    public Result deleteMainframe(@RequestBody List<String> id){
        int i=mainframeService.deleteMainframe(id);

        return i > 0?new Result(200,"删除成功"):new Result(500,"删除失败");

    }

    @PostMapping("/editMainframe")
    public Result editMainframe(@RequestBody Mainframe mainframe){
        log.info("编辑设备参数：{}",mainframe);
        if(0==mainframe.getState()){
            mainframe.setResult("close");

        }else if(1==mainframe.getState()){
            mainframe.setResult("");

        }

        int i = mainframeDao.editMainframe(mainframe);


        if(i>0&&"定时".equals(mainframe.getType())){
            ScheduledTaskRegistrar scheduledTaskRegistrar=new ScheduledTaskRegistrar();
            scheduledTaskRegistrar.addTriggerTask(
                    //1.添加任务内容(Runnable)，可以为方法
                    () -> {
                        try {
                            scan(mainframe);
                        } catch (MqttException | InterruptedException e) {
                            e.printStackTrace();
                        }
                    },
                    //2.设置执行周期(Trigger)
                    triggerContext -> {
                        //2.1 从数据库获取执行周期，在这里调用不同的方法返回不同的定时任务信息
                        System.out.println(mainframe);
                        //2.2 合法性校验.
                        if (StringUtils.isEmpty(mainframe)) {
                            // Omitted Code ..
                            log.info("计划任务为空");
                            return  null;
                        }
                        //2.3 返回执行周期(Date)
                        return new CronTrigger(mainframe.getType()).nextExecutionTime(triggerContext);
                    }
            );
        }
        return i > 0?new Result(200,"更新成功",mainframe):new Result(500,"更新失败",mainframe);
    }


    @PostMapping("/getAllmainfram")
    public List<Mainframe> getAllmainfram(@RequestBody Mainframe mainframe){
        List<Mainframe> list = mainframeService.getAllmainframe();
        String topic_id=list.stream().map(n ->String.valueOf(n.getId())).collect(Collectors.joining("\",\"", "\"", "\""));
        log.info(topic_id);

        return list ;
    }


    @GetMapping("/getAllPort")
    public Result getAllPort(@RequestParam(name = "port", required = false) String port){
        List<String> list = mainframeService.getAllPort(port);

        return new Result(200,"调用成功",list);

    }

    @GetMapping("/getAllType")
    public Result getAllType(@RequestParam(name = "type", required = false) String type){
        List<String> list = mainframeService.getAllType(type);

        return new Result(200,"调用成功",list);

    }

    @GetMapping("/getAllFloorRoom")
    public Result getAllFloorRoom(@RequestParam(name = "floor_level", required = false) String floor_level,
                             @RequestParam(name = "room_num", required = false) String room_num){
        List<Map> list = mainframeService.getAllFloorRoom(floor_level,room_num);

        return new Result(200,"调用成功",list);

    }



    @GetMapping("/getCountByType")
    public Result getCountByType(){
        Map map = mainframeService.getCountByType();
        int allmain=Integer.valueOf(map.get("allmain").toString());
        int close=Integer.valueOf(map.get("close").toString());
        int zl=allmain-close;
        map.put("zl",zl);
        return new Result(200,"调用成功",map);

    }


    @GetMapping("/getCountByLevel")
    public Result getCountByLevel(@RequestParam(name = "floor_level", required = false) String floor_level){
        Map map  = mainframeService.getCountByLevel(floor_level);
        int allmain=Integer.valueOf(map.get("allmain").toString());
        int close=Integer.valueOf(map.get("close").toString());
        int zl=allmain-close;
        map.put("zl",zl);
        return new Result(200,"调用成功",map);

    }


    @GetMapping("/getLog")
    public Result getLog( @RequestParam(name = "pageNum", required = false, defaultValue = "1") int pageNum,
                          @RequestParam(name = "pageSize", required = false, defaultValue = "10") int pageSize,
                          @RequestParam(name = "code", required = false) String code,
                         @RequestParam(name = "operate", required = false) String operate){
        PageInfo<Map> map  = mainframeService.getLog(pageNum,pageSize,code,operate);
        return new Result(200,"调用成功",map);

    }



    @GetMapping("/getMessage")
    public Object getMessage(
            @RequestParam(name = "pageNum", required = false, defaultValue = "1") int pageNum,
            @RequestParam(name = "pageSize", required = false, defaultValue = "10") int pageSize,
            @RequestParam(name = "operate", required = false) String operate
    ) {
        PageInfo<Map> map  = mainframeService.getMessage(pageNum,pageSize, operate);
        return new Result(200,"调用成功",map);
    }


    @GetMapping("/updateMessage")
    public Result updateMessage(@RequestParam(name = "id", required = false) String id){
        mainframeService.updateMessage(id);
        return new Result(200,"调用成功");

    }



    @PostMapping("/operate")
    public  Result  operate(@RequestBody List<MainframeScan> mainframeScan) throws MqttException, InterruptedException {
        //Lock lock = new ReentrantLock()

            for (MainframeScan c : mainframeScan) {
                Date datenow = new Date();
                SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                log.info("加锁时间:{}",c.getCode()+":"+ft.format(datenow));
                String random=random();
                if ("scan".equals(c.getType()) || "init".equals(c.getType())) {
                    Mainframe main = mainframeService.getMainframeByCode(c.getCode());
                    log.info("推送消息：{}，{}", c.getType() + "#" + main.getPayload(), "device_sub:" + c.getCode());
                    mqttGateway.sendToMqtt(c.getType() + "#" + main.getPayload(), "device_sub:" + c.getCode());
                    mqttGateway.sendToMqtt(c.getType() + "#" + main.getPayload(), "device_pub:" + c.getCode());


                    //publish(c.getCode());


                    String code1 = "device_sub:" + c.getCode();
                    String code2 = "device_pub:" + c.getCode();
                    subscribe(code1, c.getOperate(), random);
                    subscribe(code2, c.getOperate(), random);
//                    CompletableFuture noReturn = CompletableFuture.runAsync(()-> {
//                        try {
//                            Thread.sleep(5000L);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                    });
                    Thread.sleep(150000);
                    //查询本次消息是否过期
                    String concat=mainframeDao.getMainframeScanResultbyrandom(c.getCode(),random);
                    log.info("扫描结果：{}",random+":"+concat);
                    if(org.apache.commons.lang3.StringUtils.isBlank(concat)){
                        Log log = new Log();
                        log.setRemark(c.getCode() + "故障");
                        //*========数据库日志=========*//
                        log.setTopic(c.getCode());
                        log.setOperate(c.getOperate());
                        log.setCreate_time(new Date());
                        //保存数据库
                        logDao.insert(log);

                        mainframeDao.updateMainframeResult(c.getCode(),"gz",random +"gz");

                        Mainframe mainframe=  mainframeDao.getMainframeByCode(c.getCode());
                        Message message = new Message();
                        message.setMessage(mainframe.getRoom_num() + ("scan".equals(c.getType()) ? "扫描" : "初始化")+"故障");
                        message.setOperate(c.getOperate());
                        message.setCreate_time(new Date());
                        message.setFlag("0");

                        messageDao.inserMessage(message);

                    }else{
                        if(concat.contains("bj")){
                            Log log = new Log();
                            log.setRemark(c.getCode() + "报警");
                            //*========数据库日志=========*//
                            log.setTopic(c.getCode());
                            log.setOperate(c.getOperate());
                            log.setCreate_time(new Date());
                            //保存数据库
                            logDao.insert(log);

                            mainframeDao.updateMainframeResult(c.getCode(),"bj",random +"bj");
                            Mainframe mainframe=  mainframeDao.getMainframeByCode(c.getCode());
                            Message message = new Message();
                            message.setMessage(mainframe.getRoom_num() + ("scan".equals(c.getType()) ? "扫描" : "初始化")+ "异常告警");
                            message.setOperate(c.getOperate());
                            message.setCreate_time(new Date());
                            message.setFlag("0");
                            messageDao.inserMessage(message);
                        }else{

                            Log log = new Log();
                            log.setRemark(c.getCode() + "正常");
                            //*========数据库日志=========*//
                            log.setTopic(c.getCode());
                            log.setOperate(c.getOperate());
                            log.setCreate_time(new Date());
                            //保存数据库
                            logDao.insert(log);

                            mainframeDao.updateMainframeResult(c.getCode(),"zc",random +"zc");
                            Mainframe mainframe=  mainframeDao.getMainframeByCode(c.getCode());
                            Message message = new Message();
                            message.setMessage(mainframe.getRoom_num() + ("scan".equals(c.getType()) ? "扫描" : "初始化")+ "正常");
                            message.setOperate(c.getOperate());
                            message.setCreate_time(new Date());
                            message.setFlag("0");
                            messageDao.inserMessage(message);

                        }
                    }
                } else if ("close".equals(c.getType())) {
                    mainframeService.closeMainframeResult(c.getCode(), c.getOperate());
                }



        }

        return new Result(200, "调用成功");
    }


    @PostMapping("/scan")
    public Result  scan(@RequestBody List<MainframeScan> mainframeScan) throws MqttException, InterruptedException {
        int count=mainframeScan.size();

        List<String> list= new ArrayList();

        String random=random();
        for (MainframeScan c : mainframeScan) {

            if("scan".equals(c.getType())){

                mqttGateway.sendToMqtt(c.getCode(), "device_sub:"+c.getCode());
                mqttGateway.sendToMqtt(c.getCode(), "device_pub:"+c.getCode());

                //publish(c.getCode());
                String code1="device_sub:"+c.getCode();
                String code2="device_pub:"+c.getCode();
                subscribe(code1,c.getOperate(), random);
                subscribe(code2,c.getOperate(), random);

                list.add(c.getCode());
            }
        }

        Thread.sleep(mainframeScan.size()*150000);
        int a=mainframeService.getScanMainFrame(list);
        Map map=new HashMap();
        map.put("count",a/count);

        return new Result(200, "调用成功",map);
    }


}
